package com.vpt.lambda;


import static org.junit.Assert.assertTrue;

import java.util.Arrays;
import java.util.Comparator;
import java.util.IntSummaryStatistics;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.function.Function;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.junit.Test;

public class Introduction {
	protected UnaryOperator<Integer> factorial = i -> i == 0 ? 1 : i * this.factorial.apply(i - 1);

	/*
	 * 随着回调模式和函数式编程风格的日益流行，我们需要在Java中提供一种尽可能轻量级的将代码封装为数据（Model code as
	 * data）的方法。匿名内部类并不是一个好的选择，因为：
	 * 
	 * <ul> <li> 语法过于冗余 </li> <li> 匿名类中的this和变量名容易使人产生误解 </li> <li>
	 * 类型载入和实例创建语义不够灵活 </li> <li> 无法捕获非final的局部变量 </li> <li> 无法对控制流进行抽象 </li>
	 * </ul> 上面的多数问题均在Java SE 8中得以解决：
	 * 
	 * 通过提供更简洁的语法和局部作用域规则，Java SE 8彻底解决了问题1和问题2 通过提供更加灵活而且便于优化的表达式语义，Java SE
	 * 8绕开了问题3 通过允许编译器推断变量的“常量性”（finality），Java SE 8减轻了问题4带来的困扰 不过，Java SE
	 * 8的目标并非解决所有上述问题。因此捕获可变变量（问题4）和非局部控制流（问题5）并不在Java SE
	 * 8的范畴之内。（可能会在未来提供对这些特性的支持）
	 */
	
	// λ表达式本质上是一个匿名方法,形如：
	public int add(int x, int y) {
		return x + y;
	}
	/*
	 * lambda表示法为(int x,int y)->return x+y;java编辑器会根据上下文推断出来。 λ表达式有三部分组成
	 * 参数列表，->和表达式块 void 实现 ()->{...}; 有参数：c->{return c.method();},此处省略了括号
	 */

	/*
	 * λ表达式的类型，叫做目标类型(target type) λ表达式的目标类型是"函数接口(functional interface)"
	 * 函数接口定义：一个接口，如果只有一个显式声明的抽象方法，那么它就是一个函数接口。一般用
	 * {@link @FunctionalInterface}标注出来（也可以不标），使用这个注解是一个设计意图，如{@link @Override}
	 * to see{@link Runnable},{@link Callable},{@link ActionListener},{@link
	 * java.util.Comparator}
	 * 
	 * to see:<href
	 * src="http://blog.csdn.net/ioriogami/article/details/12782141/" />
	 * 
	 * {@link Function,Consumer,Predicate}
	 * see also{@link Optional}
	 */
	
	// 示例1
	@Test
	public void testRunnableAsLambda() {
		
		new Thread(new Runnable() {

			@Override
			public void run() {
				System.out.println("This is from an anonymous class.");

			}
		}).start();
	
		
		new Thread(() -> {
			System.out.println("This is from an anonymous method (lambda exp).");
		}).start();
	}

	// 示例2
	@Test
	public void testOutIteratorAndInnerInterator() {
		
		long sum1 = 0, sum2 = 0;

		InnerSupportor supportor = new InnerSupportor();
		List<Integer> list = supportor.generateArray(100);

		for (int i : list) {
			sum1 += i;
		}

		sum2 = list.parallelStream().collect(Collectors.summarizingInt(i -> i)).getSum();

		assertTrue(sum1 == sum2);
	}

	private static class InnerSupportor {
		private List<Integer> generateArray(int initSize) {
			List<Integer> list = new LinkedList<>();
			Random r = new Random();

			for (int i = 0; i < initSize; i++) {
				list.add(r.nextInt(100));
			}

			return list;
		}
	}

	// 示例3
	@Test
	public void primaryOccurrrence() {
		List<Integer> list = new InnerSupportor().generateArray(300);
		System.out.println(list);
		Map<Integer, IntSummaryStatistics> summaryCount = list.stream().map(e -> new Integer(e))
				.filter(Primes::isPrime)
				.collect(Collectors.groupingBy(p -> p, Collectors.summarizingInt(p -> 1)));
		long sum = 0;
		for (Entry<Integer, IntSummaryStatistics> entry : summaryCount.entrySet()) {
			System.out.println(entry.getKey() + ":" + entry.getValue().getCount());
			sum += entry.getKey();
		}

		Integer r = list.stream().filter(i -> Primes.isPrime(i) && i > 1).distinct().reduce((x, y) -> x + y).get();
		
		//list.parallelStream().filter(Primes::isPrime).distinct().reduce((x, y) -> x + y).get();
		assertTrue(r == sum);
	}

	// 示例4
	@Test
	public void nestedLambda() throws Exception {
		Callable<Runnable> c1 = () -> () -> {
			System.out.println("Nested lambda");
		};
		c1.call().run();

		Callable<Integer> c2 = Primes.isPrime(7) ? () -> 42 : () -> 27;
		System.out.println(c2.call());

		//System.out.println(factorial.apply(4));
		// 不支持
		//int five = ( (x, y) -> x + y ) (2, 3);

	}

	// effectively final
	//Java要求本地变量final或者effectively final的原因是多线程并发问题。内部类、λ表达式都有可能在不同的线程中执行，允许多个线程同时修改一个本地变量不符合Java的设计理念。
	// 示例5
	@Test
	public void testEffectivelyFinal() {
		@SuppressWarnings("unused")
		class EnclosingClass {
			int tmp1 = 1;
			int tmp2=2;
			class InnerClass {
				void invoke() {
					int tmp3 = 3;
					final int tmp4 = 4;
					int tmp5 = 5;

					Function<Integer, Integer> f1 = i -> i + tmp1;
					Function<Integer,Integer> f2=i->i+tmp2;
					tmp2=10;
					Function<Integer, Integer> f3 = i -> i + tmp3;
					Function<Integer, Integer> f4 = i -> i + tmp4;

//					Function<Integer, Integer> f5 = i -> {
//						tmp5 += i;
//						return tmp5;
//					};
				}

			}
		}
	}
	//示例6
	//方法引用，任何一个λ表达式都可以代表某个函数接口的唯一方法的匿名描述符。
	//Intege::parseInt 静态方法引用
	//System.out::print 实例方法引用
	//Person::new 构造器引用
	@Test
	public void methodReference(){
		//方法引用返回类型不是{@link Method}而是Method所属的{@link Type}
		Comparator<Integer> c2=Integer::compareTo;
		Comparator<Integer> c1=(x,y)->Integer.compare(x,y);
		
		Arrays.asList(c1.getClass().getMethods()).forEach(e->System.out.println(e.getName()+":"+e.getParameterCount()));
		System.out.println("===========================");
		Arrays.asList(c2.getClass().getMethods()).forEach(System.out::println);
	}
	
	//示例7
	//生成器函数
	@Test
	public void generatorFunction(){
		Stream.generate(Math::random).forEach(System.out::println);
	}

}